package org.glorylight.hacks.social.service;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.apache.commons.lang3.ArrayUtils;
import org.glorylight.hacks.social.data.UserData;
import org.glorylight.hacks.social.model.CompositeUserRole;
import org.glorylight.hacks.social.model.Role;
import org.glorylight.hacks.social.model.User;
import org.glorylight.hacks.social.model.UserNetwork;
import org.glorylight.hacks.social.model.UserRole;
import org.glorylight.hacks.social.util.ModelHelper;
import org.glorylight.hacks.social.util.UUIDHelper;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

@Service
@Transactional(readOnly = true)
public class UserService extends BaseService {
	
	private static final Logger log = LoggerFactory.getLogger(UserService.class);
	
	@Transactional(readOnly = false)
	public void addUser(UserData userData) throws Exception {
		log.debug("adding new user for: {}", userData.getEmailAddress());
		User user = ModelHelper.convertUserData(userData);
		user.setPassword(ArrayUtils.toObject(DigestUtils.appendMd5DigestAsHex(
                ArrayUtils.toPrimitive(user.getPassword()), new StringBuilder()).toString().getBytes()));
		Role role = em.find(Role.class, "USER");
		CompositeUserRole compositeUserRole = new CompositeUserRole(user, role);
		role.getUsers().add(new UserRole(compositeUserRole));
		add(user);
	}
	
	@Transactional(readOnly = false)
	public void deleteUser(UserData userData) throws Exception{
		log.debug("delete user for: {}", userData.getEmailAddress());
		User user = findUser(userData.getEmailAddress());
		delete(user);
	}
	
	@Transactional(readOnly = false)
	public void updateUser(UserData userData) throws Exception {
		log.debug("updating user for: {}",userData.getEmailAddress());
		User user = em.find(User.class, userData.getEmailAddress());
		User userSource = ModelHelper.convertUserData(userData);
		user.setBirthDate(userSource.getBirthDate());
		user.setBabyName(userSource.getBabyName());
		user.setBabyBirthDate(userSource.getBabyBirthDate());
		user.setGender(userSource.getGender());
		user.setMobileNo(userSource.getMobileNo());
		user.setActivate(userSource.isActivated());
		if(userSource.getPassword() != null)
			user.setPassword(ArrayUtils.toObject(DigestUtils.appendMd5DigestAsHex(
					ArrayUtils.toPrimitive(userSource.getPassword()), new StringBuilder()).toString().getBytes()));
		update(user);
	}

	public UserData find(String email) {
		if (log.isDebugEnabled())
			log.debug("retrieve user: {}", email);
		User user = findUser(email);
		if (user != null) {
			UserData userData = ModelHelper.convertUser(user);
			userData.setUserId(UUIDHelper.uuidToString(user.getUserId()));
			return userData;
		} else
			return null;
	}
	
//	@Cacheable(value = "user", key = "#email")
	public User findUserForCredential(String email) {
		return findUser(email);
	}
	
	public List<User> findConnectionToUser(String email) {
		//yg ngefollow
		User user = findUser(email);
		@SuppressWarnings("unchecked")
		List<UserNetwork> userNetworks = (List<UserNetwork>)em.createNamedQuery("network-find-follower").setParameter("userId", user.getUserId()).getResultList();
		List<User> users = new ArrayList<User>();
		for(UserNetwork userNetwork : userNetworks) {
			users.add(userNetwork.getUser());
		}
		return users;
	}
	
	@Cacheable(value = "user-networks", key = "#email")
	public List<User> findUserToConnection(String email) {
		//yg gw follow
		User user = findUser(email);
		List<User> users = new ArrayList<User>();
		Hibernate.initialize(user.getNetworks());
		for(UserNetwork userNetwork : user.getNetworks()) {
			users.add(findUserId(userNetwork.getConnectTo()));
		}
		return users;
	}
	
	private User findUser(String email) {
		if (log.isDebugEnabled())
			log.debug("retrieve user: {}", email);
		return em.find(User.class, email);
	}
	
	public User findUserId(UUID userId) {
		log.debug("find userid : {}", UUIDHelper.uuidToString(userId));
		return em.createNamedQuery("user-by-userid", User.class).setParameter("userId", userId).getSingleResult();
	}
	
	public List<UserData> findAll() {
		if (log.isDebugEnabled())
			log.debug("find all user");
		List<User> users = em.createQuery("from User", User.class).getResultList();
		List<UserData> datas = null;
		if (users.size() > 0){
			datas = new ArrayList<UserData>();
			for (User u : users)
				datas.add(ModelHelper.convertUser(u));
		}
		
		return datas;
	}
	
}
